//
//  RBLocationManager.m
//  FD
//
//  Created by xiaofang wang on 2018/10/30.
//  Copyright © 2018年 ZhiYuan Network. All rights reserved.
//

#import "RBLocationManager.h"
@interface RBLocationManager()<CLLocationManagerDelegate>
{
    RBLocationComplectionBlock  _locationComplectionBlock;
    BOOL _keepLocation; //持续定位
    RBLocationFailBlock _failBlock;
    
    CLLocationDistance _delayDistance; //超出距离
    NSTimeInterval _delayTime; ///超出时间
}
/**系统定位管理类*/
@property (nonatomic, strong) CLLocationManager *locationMgr;
/**推迟更新*/
@property (nonatomic, assign) BOOL deferringUpdates;


@end

@implementation RBLocationManager

+ (RBLocationManager *)shareInstance {

    static RBLocationManager *rbLocationMgr = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        rbLocationMgr = [[RBLocationManager alloc] init];
        
        [rbLocationMgr initLocationManager]; //为什么不能用self调用。因为这是 + , 对象调方法是没有问题的。
    });
    
    return rbLocationMgr;
}



#pragma mark - 接口
/**2.申请定位权限
 需要在info.plist 中添加如下字段
 Privacy - Location When In Use Usage Description
 Privacy - Location Always Usage Description
 */
- (void)requestLocationPermission
{
    
    //iOS9.0以上系统除了要配置info.plist之外，还要添加如下代码,才能实现后台定位，否则会会crash
    if (@available(iOS 9.0, *)) {
        _locationMgr.allowsBackgroundLocationUpdates = YES;
    }else {
        //
    }
    
    [_locationMgr requestAlwaysAuthorization]; //一直保持定位
//    [_locationMgr requestWhenInUseAuthorization];//使用期间定位
}



/**3.查看定位权限*/
- (BOOL)checkLocationPermission
{
    if ([CLLocationManager locationServicesEnabled]) { //允许定位
        switch ([CLLocationManager authorizationStatus]) { //查看定位权限
            case kCLAuthorizationStatusNotDetermined:
                FDLog(@"用户尚未进行选择");
                break;
            case kCLAuthorizationStatusRestricted:
                FDLog(@"定位权限被限制");
                break;
            case kCLAuthorizationStatusAuthorizedAlways:
            case kCLAuthorizationStatusAuthorizedWhenInUse:
                FDLog(@"允许定位");
                return YES;
                break;
            case kCLAuthorizationStatusDenied:
                FDLog(@"不允许定位");
                break;
            default:
                
                break;
        }
    }
    
    return NO;
}




/**4.获取当前定位
 desiredAccurancy 定位精准度
 */
- (void)updateLocationWithDesiredAccurancy:(CLLocationAccuracy)desiredAccurancy complectionBlock:(RBLocationComplectionBlock)complection failureBlcok:(RBLocationFailBlock)failure
{
    _locationComplectionBlock = complection;
    _failBlock = failure;
    _keepLocation = NO;  // 不持续定位
    self.locationMgr.desiredAccuracy = desiredAccurancy;
    
    //开始定位
    [self.locationMgr startUpdatingLocation];
}


/**5. 持续获取当前定位*/
- (void)keepUpdateLocationWithDesiredAccuracy:(CLLocationAccuracy)desiredAccuracy distanceFilter:(CGFloat)distanceFilter complectionBlock:(RBLocationComplectionBlock)complection failBlock:(RBLocationFailBlock)failure
{
    _locationComplectionBlock = complection;
    _failBlock = failure;
    _keepLocation = YES; //持续定位
    
    self.locationMgr.desiredAccuracy  = desiredAccuracy;
    self.locationMgr.distanceFilter = distanceFilter;
    
    
    //开始定位
    [self.locationMgr startUpdatingLocation];
}



/**6.后台持续定位*/
- (void)keepUpdateLocationInBackgroundWithDesiredAccuracy:(CLLocationAccuracy)desiredAccuracy distanceFilter:(CGFloat)distanceFilter complectionBlock:(RBLocationComplectionBlock)complection failBlock:(RBLocationFailBlock)failure
{

    //获取系统版本
    CGFloat systemVersion = [[[UIDevice currentDevice] systemName] floatValue];
    
    if (systemVersion >= 9.0) { //iOS9.0持续定位
        self.locationMgr.allowsBackgroundLocationUpdates = YES;
    }else if(systemVersion >= 8.0) {
        
        //在后台也可定位
        [self.locationMgr requestAlwaysAuthorization];
    }
    
    //tips:定位权限为“使用期间的时候” ，程序在后台运行时会在顶部有一条蓝色的信息框； “定位权限为始终的时候，就不会有蓝色框了”
    
    
    //系统是否可以自行中断程序的定位功能
    self.locationMgr.pausesLocationUpdatesAutomatically = NO;
    
    
    [self keepUpdateLocationWithDesiredAccuracy:desiredAccuracy distanceFilter:distanceFilter complectionBlock:complection failBlock:failure];
}



/**7.停止获取定位*/
- (void)stopUpdateLocation
{
    [self.locationMgr stopUpdatingLocation];//停止定位
    _keepLocation = NO; //不持续定位
    _locationComplectionBlock = nil;//block 置nil
    
    
    //系统可以自动暂停定位
    self.locationMgr.pausesLocationUpdatesAutomatically = YES;
}





/**8.获取指南针信息*/
//- (void)

/**9.停止获取指南针信息*/

/**10.地理编码*/
- (void)geocodeAddressString:(NSString *)address complectionBlock:(RBPlacemarkComplectionBlock)complection failBlock:(RBLocationFailBlock)failure
{
 
    //地理编码
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {

        //失败回调
        if (error) {
            if (failure) { //只要当这个block实现了才进行回调
                failure(error);
            }
            return ;
        }
        
        //成功回调 placemark:地表
        complection(placemarks.lastObject);
    }];
}


/**11.反地理编码*/
- (void)reverseGeocodeLocation:(CLLocation *)location complectionBlock:(RBPlacemarkComplectionBlock)complection failBlock:(RBLocationFailBlock)failure
{
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        if (error) {
            if(failure){
                failure(error);
            }
            return ;
        }
        
        complection(placemarks.lastObject);
    }];
}

- (void)reverseGeocodeCoordinate:(CLLocationCoordinate2D)coordinate complectionBlock:(RBPlacemarkComplectionBlock)complection failBlock:(RBLocationFailBlock)failure
{
    CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
    
    [self reverseGeocodeLocation:location complectionBlock:complection failBlock:failure];
}


/** 12. 后台定位低功耗设置，设置后，当定位超过该距离或超过该时间后才会去进行下一次定位，避免多次定位导致增加耗电量
 distance:距离(米)
 timeout: 超时时间(秒)
 */
- (void)delayUpdateLocationWithDistance:(CLLocationDistance)distance timeout:(NSTimeInterval)timeout
{
    _delayDistance = distance;
    _delayTime = timeout;
    
    self.deferringUpdates = YES;
}


/**13 取消低功耗设置*/
- (void)cancelDelayUpdateLocation
{
    self.deferringUpdates = NO;
}


#pragma mark - Private
/**初始化系统定位信息管理类*/
- (void)initLocationManager {
    _locationMgr = [[CLLocationManager alloc] init];
    _locationMgr.delegate = self;
}

#pragma mark - 三 CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
    
    //回调定位结果
    if (_locationComplectionBlock) {
        _locationComplectionBlock(locations.lastObject);
    }
    
    if (_keepLocation == NO) {
        [self.locationMgr stopUpdatingLocation];
    }
    
    if (self.deferringUpdates == YES) {
        FDLog(@"低功耗设置");
        
        [self.locationMgr allowDeferredLocationUpdatesUntilTraveled:_delayDistance timeout:_delayTime];
    }else {
        FDLog(@"没有低功耗设置");
    }
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    if (error.code == kCLErrorLocationUnknown) {
        FDLog(@"无法检索位置");
    }else if (error.code == kCLErrorNetwork) {
        FDLog(@"网络错误");
    }else if(error.code == kCLErrorDenied) {
        FDLog(@"定位权限问题");
        //停止定位
        [self.locationMgr stopUpdatingLocation];
        //指针清零
        self.locationMgr = nil;
    }
    
    //回调错误
    if (_failBlock) {
        _failBlock(error);
    }
}

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    
}

/**14.计算两个坐标之间的距离 单位m*/
- (CLLocationDistance)calculateDistanceWithLoc1:(CLLocation *)loc1 loc2:(CLLocation *)loc2 {
    CLLocationDistance distance =  [loc1 distanceFromLocation:loc2];
    return distance;
}

@end
